/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "nci_feature.h"
#include "nci_nfcee.h"
#include "nci_base.h"
#include "nfc_log_api.h"
#include "ee_int.h"
#include "nci_task.h"

#if IS_FEATURE_ON(NCI_FEATURE_EE)

/**
 * @file nci_nfcee.c
 * @brief NCI NFCEE相关API实现
*/

/**
 * @brief nci_nfcee_discover的ntf_wait_cback回调
 */
static bool nfcee_discover_ntf_wait_cback(tNCI_HEAD cmd, tNCI_BUF *rsp, tNCI_WAIT_BUF *p_ntf_wait_list, uint8_t ntf_wait_list_size, tNCI_STATUS *p_return_status) {
    (void) cmd;
    if (!rsp || rsp->len < 2 || !rsp->data) {
        NFCLOG_E("invalid rsp");
        return false;
    }
    if (!p_ntf_wait_list) {
        NFCLOG_E("invalid ntf_wait_list");
        return false;
    }
    uint8_t nfcee_num = rsp->data[1]; // NFCEE数量
    NFCLOG_I("nfcee_num = %d", nfcee_num);
    uint8_t received_ntf_count = 0;
    for (uint8_t i = 0; i < ntf_wait_list_size; i++) {
        tNCI_WAIT_BUF *p_ntf_wait_buf = &p_ntf_wait_list[i];
        if (p_ntf_wait_buf->is_received) {
            received_ntf_count++;
        }
    }
    if (received_ntf_count >= nfcee_num) {
        // 已经接收到所有NFCEE DISCOVER NTF
        NFCLOG_I("all ntf received");
        *p_return_status = NCI_STATUS_OK;
        return true;
    }
    NFCLOG_I("received ntf = %d/%d", received_ntf_count, nfcee_num);
    return false;
}

/**
 * @brief 发现NFCEE
 *
 * @param[out] infos 存储NFCEE信息
 * @param[out] count 返回的NFCEE个数
 *
 * @return 成功返回NCI_STATUS_OK，失败返回错误码
*/
tNCI_STATUS nci_nfcee_discover(tNCI_NFCEE *infos, uint8_t *count) {
    if (infos == NULL || count == NULL) {
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_BUF *cmd = alloc_nci_buf(NCI_NFCEE_DISCOVER_CMD);
    tNCI_BUF *rsp = alloc_nci_buf(NCI_NFCEE_DISCOVER_RSP);
    tNCI_WAIT_BUF *p_ntf_wait_list = osi_calloc(NCI_MAX_NFCEE_SUPPORT * sizeof(tNCI_WAIT_BUF));
    tNCI_STATUS ret = NCI_STATUS_FAILED;
    if (cmd == NULL || rsp == NULL || p_ntf_wait_list == NULL) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }
    for (uint8_t i = 0; i < NCI_MAX_NFCEE_SUPPORT; i++) {
        tNCI_BUF *p_ntf = alloc_nci_buf(NCI_NFCEE_DISCOVER_NTF);
        if (!p_ntf) {
            NFCLOG_E("alloc nci buf failed, index = %d", i);
            ret = NCI_STATUS_EXT_ALLOC_FAILED;
            goto cleanup;
        }
        SET_WAIT_BUF(p_ntf_wait_list[i], NCI_NFCEE_DISCOVER_NTF, NCI_STATUS_OK, p_ntf);
    }

    *count = 0;

    ret = nci_tp_send_nci_get_rsp_wait_ntf(cmd, rsp, NCI_DEFAULT_WAIT_TIME, false, p_ntf_wait_list, NCI_MAX_NFCEE_SUPPORT, nfcee_discover_ntf_wait_cback);

    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    for (uint8_t i = 0; i < NCI_MAX_NFCEE_SUPPORT; i++) {
        if (!p_ntf_wait_list[i].is_received) {
            NFCLOG_W("nfcee ntf[%d] not received", i);
            continue;
        }
        tNCI_BUF *p_ntf = p_ntf_wait_list[i].buf;
        if (!p_ntf) {
            NFCLOG_E("nfcee ntf[%d] is NULL", i);
            continue;
        }

        tNCI_NFCEE *info = &infos[*count];
        uint8_t *p = p_ntf->data;
        STREAM_TO_UINT8(info->nfcee_id, p);
        STREAM_TO_UINT8(info->status, p);
        STREAM_TO_UINT8(info->num_of_protocol, p);
        STREAM_TO_ARRAY(info->protocols, p, info->num_of_protocol);
        STREAM_TO_UINT8(info->num_of_tlvs, p);

        for (uint8_t j = 0; j < info->num_of_tlvs; j++) {
            STREAM_TO_UINT8(info->tlvs[j].type, p);
            STREAM_TO_UINT8(info->tlvs[j].length, p);
            STREAM_TO_ARRAY(info->tlvs[j].value, p, info->tlvs[j].length);
        }

        uint8_t nfcee_power_supply;
        STREAM_TO_UINT8(nfcee_power_supply, p);

        info->nfcc_power_ctrl = (nfcee_power_supply == 1);

        *count += 1;
    }
cleanup:
    free_nci_buf(cmd);
    free_nci_buf(rsp);
    if (p_ntf_wait_list) {
        for (uint8_t i = 0; i < NCI_MAX_NFCEE_SUPPORT; ++i) {
            free_nci_buf(p_ntf_wait_list[i].buf);
        }
        osi_free(p_ntf_wait_list);
    }
    return ret;
}

/**
 * @brief 设置NFCEE状态
 *
 * @param nfcee_id 需要控制的NFCEE ID
 * @param mode 切换的模式
 *
 * @return 成功返回NCI_STATUS_OK，失败返回错误码
 */
tNCI_STATUS nci_nfcee_mode_set(uint8_t nfcee_id, tNCI_EE_MODE mode) {

    tNCI_BUF *cmd = alloc_nci_buf(NCI_NFCEE_MODE_SET_CMD);
    tNCI_BUF *ntf = alloc_nci_buf(NCI_NFCEE_MODE_SET_NTF);
    tNCI_STATUS ret = NCI_STATUS_FAILED;
    if (cmd == NULL || ntf == NULL) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }

    UINT8_TO_BUF(cmd, nfcee_id);
    UINT8_TO_BUF(cmd, mode);

    ret = nci_tp_send_nci_get_rsp_ntf(cmd, NULL, ntf, true, NCI_DEFAULT_WAIT_TIME);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    uint8_t *p = ntf->data;
    STREAM_TO_UINT8(ret, p);

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(ntf);
    return ret;
}

/**
 * @brief 设置NFCEE电源状态
 *
 * @param nfcee_id 需要控制的NFCEE ID
 * @param cfg 电源控制配置
 *
 * @return 成功返回NCI_STATUS_OK，失败返回错误码
 */
tNCI_STATUS nci_nfcee_power_and_link_cntrl(uint8_t nfcee_id, tNCI_EE_POWER_AND_LINK_CFG cfg) {
    tNCI_BUF *cmd = alloc_nci_buf(NCI_NFCEE_POWER_AND_LINK_CNTRL_CMD);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, nfcee_id);
    UINT8_TO_BUF(cmd, cfg);

    tNCI_STATUS ret = nci_tp_send_nci(cmd);

    free_nci_buf(cmd);
    return ret;
}

/**
 * @brief 处理NFCEE发现通知
 */
static void nci_nfcee_discover_ntf(uint8_t *data, uint16_t len) {
    (void) data;
    NFCLOG_E("unexpected ntf received, len=%d", len);
}

/**
 * @brief 处理NFCEE状态通知
 */
static void nci_nfcee_status_ntf(uint8_t *data, uint16_t len) {
    if (data == NULL || len < 2) {
        NFCLOG_E("invalid param");
        return;
    }
    nci_task_post(NCI_TASK_EVT_EE_STATUS_NTF, data[0], data[1], NULL);
}

/**
 * @brief 处理NFCEE相关的通知
 *
 * @param oid 通知的OID
 * @param data 通知的payload数据，不包含NCI头
 * @param len 通知的payload长度
 */
void nci_nfcee_ntf_handle(uint8_t oid, uint8_t *data, uint16_t len) {
    switch (oid) {
        case NCI_NFCEE_DISCOVER:
            nci_nfcee_discover_ntf(data, len);
            break;
        case NCI_NFCEE_STATUS:
            nci_nfcee_status_ntf(data, len);
            break;
        default:
            NFCLOG_W("nci_nfcee_ntf_handle: unknown oid %d", oid);
            break;
    }
}

#endif /* NCI_FEATURE_EE */
